/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.common.misc.util;

/**
 * 平台工具类
 * <p/>
 * 忘记修改自哪里了... 原谅我..
 */
@SuppressWarnings({"unused"})
public abstract class Platform {
    public static final int UNSPECIFIED = -1;   // unspecified
    public static final int MAC = 0;            // MAC OS X
    public static final int LINUX = 1;          // Linux
    public static final int WINDOWS = 2;        // Windows
    public static final int SOLARIS = 3;        // Solaris
    public static final int FREEBSD = 4;        // FreeBSD
    public static final int OPENBSD = 5;        // OpenBSD
    public static final int WINDOWSCE = 6;      // WindowsCE
    public static final int AIX = 7;            // AIX
    public static final int ANDROID = 8;        // Android
    public static final int GNU = 9;            // GNU
    public static final int KFREEBSD = 10;      // kfreeBSD
    public static final int NETBSD = 11;        // netBSD

    /**
     * Current OS Type
     */
    private static final int OS_TYPE;

    /**
     * Current platform architecture.
     */
    private static final String ARCH;

    /**
     * Canonical resource prefix for the current platform.  This value is
     * used to load bundled native libraries from the class path.
     */
    private static final String RESOURCE_PREFIX;

    static {
        final String osName = System.getProperty("os.name", "");

        if (osName.startsWith("Linux")) {
            if ("dalvik".equals(System.getProperty("java.vm.name").toLowerCase())) {
                OS_TYPE = ANDROID;
            } else {
                OS_TYPE = LINUX;
            }
        } else if (osName.startsWith("AIX")) {
            OS_TYPE = AIX;
        } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
            OS_TYPE = MAC;
        } else if (osName.startsWith("Windows CE")) {
            OS_TYPE = WINDOWSCE;
        } else if (osName.startsWith("Windows")) {
            OS_TYPE = WINDOWS;
        } else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
            OS_TYPE = SOLARIS;
        } else if (osName.startsWith("FreeBSD")) {
            OS_TYPE = FREEBSD;
        } else if (osName.startsWith("OpenBSD")) {
            OS_TYPE = OPENBSD;
        } else if (osName.equalsIgnoreCase("gnu")) {
            OS_TYPE = GNU;
        } else if (osName.equalsIgnoreCase("gnu/kfreebsd")) {
            OS_TYPE = KFREEBSD;
        } else if (osName.equalsIgnoreCase("netbsd")) {
            OS_TYPE = NETBSD;
        } else {
            OS_TYPE = UNSPECIFIED;
        }

        ARCH = System.getProperty("os.arch", "").toLowerCase().trim();
        RESOURCE_PREFIX = getNativeLibraryResourcePrefix();
    }

    public static final int getOSType() {
        return OS_TYPE;
    }

    public static final boolean isMac() {
        return OS_TYPE == MAC;
    }

    public static final boolean isAndroid() {
        return OS_TYPE == ANDROID;
    }

    public static final boolean isLinux() {
        return OS_TYPE == LINUX;
    }

    public static final boolean isAIX() {
        return OS_TYPE == AIX;
    }

    public static final boolean isWindowsCE() {
        return OS_TYPE == WINDOWSCE;
    }

    public static final boolean isWindows() {
        return OS_TYPE == WINDOWS || OS_TYPE == WINDOWSCE;
    }

    public static final boolean isSolaris() {
        return OS_TYPE == SOLARIS;
    }

    public static final boolean isFreeBSD() {
        return OS_TYPE == FREEBSD;
    }

    public static final boolean isOpenBSD() {
        return OS_TYPE == OPENBSD;
    }

    public static final boolean isNetBSD() {
        return OS_TYPE == NETBSD;
    }

    public static final boolean isGNU() {
        return OS_TYPE == GNU;
    }

    public static final boolean iskFreeBSD() {
        return OS_TYPE == KFREEBSD;
    }

    public static final boolean isX11() {
        // TODO: check filesystem for /usr/X11 or some other X11-specific test
        return !Platform.isWindows() && !Platform.isMac();
    }

    public static final String getArch() {
        return ARCH;
    }

    public static final boolean is64Bit() {
        String model = System.getProperty("sun.arch.data.model", System.getProperty("com.ibm.vm.bitmode"));
        if (model != null) {
            return "64".equals(model);
        }

        return ("x86_64".equals(ARCH) || "ia64".equals(ARCH) || "ppc64".equals(ARCH) || "sparcv9".equals(ARCH) || "amd64".equals(ARCH));
    }

    public static final boolean isIntel() {
        return (ARCH.equals("i386") || ARCH.startsWith("i686") || ARCH.equals("x86") || ARCH.equals("x86_64") || ARCH.equals("amd64"));
    }

    public static final boolean isPPC() {
        return (ARCH.equals("ppc") || ARCH.equals("ppc64") || ARCH.equals("powerpc") || ARCH.equals("powerpc64"));
    }

    public static final boolean isARM() {
        return ARCH.startsWith("arm");
    }

    public static final boolean isSPARC() {
        return ARCH.startsWith("sparc");
    }

    public static String getResourcePrefix() {
        return RESOURCE_PREFIX;
    }

    /**
     * Generate a canonical String prefix based on the current OS type/arch/name.
     */
    private static String getNativeLibraryResourcePrefix() {
        return getNativeLibraryResourcePrefix(getOSType(), System.getProperty("os.arch"), System.getProperty("os.name"));
    }

    /**
     * Generate a canonical String prefix based on the given OS type/arch/name.
     *
     * @param osType from {@link #getOSType()}
     * @param arch   from <code>os.arch</code> System property
     * @param name   from <code>os.name</code> System property
     */
    private static String getNativeLibraryResourcePrefix(int osType, String arch, String name) {
        String osPrefix;
        arch = arch.toLowerCase().trim();
        if ("powerpc".equals(arch)) {
            arch = "ppc";
        } else if ("powerpc64".equals(arch)) {
            arch = "ppc64";
        } else if ("i386".equals(arch)) {
            arch = "x86";
        } else if ("x86_64".equals(arch) || "amd64".equals(arch)) {
            arch = "x86-64";
        }
        switch (osType) {
            case Platform.ANDROID:
                if (arch.startsWith("arm")) {
                    arch = "arm";
                }
                osPrefix = "android-" + arch;
                break;
            case Platform.WINDOWS:
                osPrefix = "win32-" + arch;
                break;
            case Platform.WINDOWSCE:
                osPrefix = "w32ce-" + arch;
                break;
            case Platform.MAC:
                osPrefix = "darwin";
                break;
            case Platform.LINUX:
                osPrefix = "linux-" + arch;
                break;
            case Platform.SOLARIS:
                osPrefix = "sunos-" + arch;
                break;
            case Platform.FREEBSD:
                osPrefix = "freebsd-" + arch;
                break;
            case Platform.OPENBSD:
                osPrefix = "openbsd-" + arch;
                break;
            case Platform.NETBSD:
                osPrefix = "netbsd-" + arch;
                break;
            case Platform.KFREEBSD:
                osPrefix = "kfreebsd-" + arch;
                break;
            default:
                osPrefix = name.toLowerCase();
                int space = osPrefix.indexOf(" ");
                if (space != -1) {
                    osPrefix = osPrefix.substring(0, space);
                }
                break;
        }
        osPrefix += "-" + arch;

        return osPrefix;
    }

    private Platform() {
    }
}
